﻿using System;
using System.Reflection;
using Ast.Framework.Environment;
using Ast.Framework.FileSystems.Paths;
using Ast.Framework.FileSystems.SiteFolders;
using Castle.Core.Logging;

namespace Ast.Framework.FileSystems.Dependencies
{
    public class DefaultAssemblyProbingFolder : IAssemblyProbingFolder
    {
        private readonly string _basePath;
        private readonly IPathProvider _pathProvider;
        private readonly IAssemblyLoader _assemblyLoader;

        public DefaultAssemblyProbingFolder(ISiteFolderRoot siteFolderRoot, IPathProvider pathProvider, IAssemblyLoader assemblyLoader)
        {
            _pathProvider = pathProvider;
            _assemblyLoader = assemblyLoader;

            _basePath = pathProvider.Combine(siteFolderRoot.Path, "Dependencies");

            Logger = NullLogger.Instance;
        }

        public ILogger Logger { get; set; }

        public bool AssemblyExists(string moduleName)
        {
            var path = PrecompiledAssemblyPath(moduleName);
            return _pathProvider.FileExists(path);
        }

        public DateTime GetAssemblyDateTimeUtc(string moduleName)
        {
            var path = PrecompiledAssemblyPath(moduleName);
            return _pathProvider.GetFileLastWriteTimeUtc(path);
        }

        public string GetAssemblyPath(string moduleName)
        {
            var path = PrecompiledAssemblyPath(moduleName);
            return _pathProvider.FileExists(path) ? path : null;
        }

        public Assembly LoadAssembly(string moduleName)
        {
            var path = PrecompiledAssemblyPath(moduleName);
            return _pathProvider.FileExists(path) ? _assemblyLoader.Load(moduleName) : null;
        }

        public void DeleteAssembly(string moduleName)
        {
            var path = PrecompiledAssemblyPath(moduleName);

            if (_pathProvider.FileExists(path))
            {
                Logger.InfoFormat("Deleting assembly for module \"{0}\" from probing directory", moduleName);
                _pathProvider.DeleteFile(path);
            }
        }

        public void StoreAssembly(string moduleName, string fileName)
        {
            var path = PrecompiledAssemblyPath(moduleName);

            Logger.InfoFormat("Storing assembly file \"{0}\" for module \"{1}\"", fileName, moduleName);
            using (var src = _pathProvider.OpenFile(fileName))
            using (var dst = _pathProvider.CreateFile(path))
            {
                src.CopyTo(dst);
            }
        }

        private string PrecompiledAssemblyPath(string moduleName)
        {
            return _pathProvider.Combine(_basePath, moduleName + ".dll");
        }
    }
}